/*
 * Copyright 2008 Neil Bacon
 * Distributed under the terms of the Mozilla Public License version 1.1
 * or the GNU General Public License version 3.
 */

package nb.ref.impl;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;

import nb.ref.HashableReference;
import nb.ref.HashableReferenceFactory;

/**
 * Produce HashableReference<V> instances based on SoftReferences.
 * @param <V>
 */
public class HashableSoftReferenceFactory<V> implements HashableReferenceFactory<V> {

    public HashableReference<V> get(V referent) {
        return new HashableSoftReference<V>(referent);
    }

    public HashableReference<V> get(V referent, ReferenceQueue<V> queue) {
        return new HashableSoftReference<V>(referent, queue);
    }


    // nested classes ...

    /**
     * A SoftReference that uses the referent object's {@link #hashCode()} and {@link #equals(Object)}.
     * @param <V>
     */
    static class HashableSoftReference<V> extends SoftReference<V> implements HashableReference<V> {

        private final int hashCode;

        public HashableSoftReference(V referent) {
            super(referent);
            hashCode = referent.hashCode();
        }

        public HashableSoftReference(V referent, ReferenceQueue<V> queue) {
            super(referent, queue);
            hashCode = referent.hashCode();
        }

        @Override
        public int hashCode() {
            return hashCode;
        }

        @SuppressWarnings("unchecked")
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            V v = get();
            if (v == null || obj == null || getClass() != obj.getClass())
                return false;
            V vOther = ((HashableReference<V>) obj).get();
            return vOther != null && v.equals(vOther);
        }

    } // class HashableSoftReference<V>

}
